Tableros de Quarto® - Shiny
Encuentro 9
Una cabecera YAML para tableros de Quarto interactivos Shiny se asemeja a un dashboard pero incorpora la opción server.
Las otras opciones conocidas para cabeceras de tableros funcionan igual (logos, botones, etc)
La estructura de este tipo de tablero consta de dos componentes principales:
la interfaz de usuario (ui)
Que es visible y la integran los dispositivos de entrada
el servidor Shiny (server)
Que no es visible y se encarga de traducir los cambios efectuados en la ui en reacciones del producto visualizado (gráfico, tabla, etc)
Además, siempre habrá una área donde se visualizan los elementos interactivos.
La interfaz de usuario puede estar compuesta por una o varias entradas de datos (inputs).
Los inputs se pueden disponer de varias formas:
Una barra lateral global se configura con:
---
title: "Mi tablero"
format: dashboard
server: shiny
---
## {.sidebar}
```{r}
# input 1
# input 2
```Se le llama global porque esta presente siempre aunque tengamos múltiples páginas y pasemos de una a otra.
Las barras laterales también se puede ubicar dentro del diseño del tablero, por ejemplo en una misma fila de dos columnas (una barra lateral y otra donde se muestra un gráfico asociado)
Las barras laterales se pueden ubicar en el lado izquierdo o derecho. También puede modificar el tamaño de las barras laterales mediante el atributo width.
Las barras de herramientas son similares a las barras laterales, pero ofrecen un diseño horizontal. Se crean agregando la clase .toolbar a un encabezado de fila de nivel 2.
Al igual que las barras laterales, las barras de herramientas pueden ser globales o en línea, es decir definidas dentro del diseño. Por ejemplo, a nivel columna.
También se puede ubicar debajo del gráfico si invertimos el orden de las filas.
Para agregar una barra de herramientas a una tarjeta, se define inmediatamente encima o debajo de la celda que genera la salida. Se puede hacer agregando el metadato content: card-toolbar a un fragmento de código R o creando un div con la clase .card-toolbar
De la misma forma se puede agregar una barra lateral solo a una tarjeta, aplicando la clase .card-sidebar
Dentro de las barras, sean estas globales, laterales, de tarjeta, etc vamos a incluir las entradas (inputs) que vienen preseteados con Shiny a modo de funciones.
Hay una variedad de posibilidades, entre las cuales se encuentra:
Hay funciones de entradas directas como numericInput() para datos numéricos, textInput() para texto y dateInput() para fechas; rangos como dateRangeInput(), botones tipo actionButton() o radioButtons() y barras de desplazamiento como sliderInput().
Los sufijos de estas funciones pueden ser generalmente Input para entradas de valores o Buttons para pulsar botones.
Todas las funciones de entrada tienen un argumento donde se define la variable que va a tomar el o los valores que el usuario determine, llamada inputID.
Esta variable será utilizada luego en la parte del servidor para reaccionar de forma interactiva a sus cambios.
Ejemplo de una función de Input numérica:
```{r}
#| content: card-sidebar
shiny::numericInput(inputID = numero,
label = "Número:",
value = 10,
min = 1,
max = 100)
```Construye un input numérico, bajo la etiqueta “Número:” con un valor predeterminado de 10, sobre una escala de 1 a 100 que se almacena en la variable numero.
Ejemplo de una función Input de botones de opción (RadioButtons):
```{r}
#| content: card-sidebar
shiny::radioButtons(inputId = "dist",
label = "Tipo de distribución:",
choices = c("Normal" = "norm",
"Uniforme" = "unif",
"Log-normal" = "lnorm",
"Exponencial" = "exp"),
selected = "Normal")
```Construye un input de botones de opción, bajo la etiqueta “Tipo de distribución:” con una opción seleccionada en “Normal”, sobre 4 opciones declaradas en choices que se almacena en la variable dist.
Ejemplo de una función Input de desplazamiento (slideInput):
```{r}
sliderInput(inputID = "obs",
label = "Número de observaciones:",
min = 0,
max = 1000,
value = 500,
step = 10
)
```Construye un input de desplazamiento, bajo la etiqueta “Número de observaciones:” con un valor predeterminado en 500 de una escala entre 0 y 1000, con saltos de 10 en 10, que se almacena en la variable obs.
El bloque servidor se declara con el metadato #| context: server. Dentro se utilizan las funciones de Shiny para hacer reactivas a los inputs a determinadas partes de lo que se está construyendo (por ejemplo: un gráfico).
También se utiliza la función reactive() en general, para construir expresiones reactivas.
La expresión va encerrada entre llaves y contiene un filtro asociado a un input numérico (input$numero). El dataframe datos va a cambiar cada vez que cambien el ingreso del número, filtrando las observaciones que tengan ese valor en var1 en los datos proveniente de la lectura (datos_leídos).
Otra función que se incluye en el bloque servidor, relacionada con gráficos es renderPlot().
```{r}
#| context: server
output$grafico <- renderPlot({
datos() |>
ggplot(aes(input$x, input$y)) +
geom_point()
```La expresión dentro de renderPlot() va entre llaves y contiene un gráfico ggplot. Las variables declaradas en x e y provienen de inputs.
La salida se almacena en la variable output$grafico que se va actualizar cada vez que el gráfico se desarrolle con variables x o y nuevas.
Toda entrada de datos interactiva va a comunicarse con el código escrito en el área servidor, como vimos en las diapositivas anteriores, y la o las salidas finales se van a mostrar en bloques de código dentro de tarjetas o dispuestas directamente en filas o columnas.
Shiny trae funciones de salidas que finalizan con la palabra Output, como plotOutput() para presentar gráficos provenientes de renderPlot() o textOutput() para textos de renderText().
Por ejemplo, para visualizar el renderPlot anterior necesitaremos hacer:
Más allá de los elementos dinámicos y/o interactivos en sus partes, lo que hace a veces interesante a un tablero es reflejar los cambios en los datos.
Ejemplos en nuestro campo de esta situación se relacionan con la vigilancia epidemiológica, donde los datos se van actualizando periódicamente (puede ser tiempo real, diario, semanal, etc).
Mostraremos un esquema de trabajo posible, (a modo de demostración) con recursos complementarios y gratuitos: la publicación de un tablero con actualización periódica programada.
Los requisitos básicos sobre los que vamos a trabajar son:
Es un sistema de control de versiones local vinculado con repositorios en línea.
Hasta ahora mostramos la creación de documentos y tableros Quarto individuales. Existen también proyectos Quarto más complejos como libros, blogs y sitios Web, que se asocian a proyectos de RStudio y contienen un conjunto de documentos Quarto.
Para que este tablero funcione dentro del servidor de alojamiento y se renderice automáticamente necesitamos configurarlo dentro de un proyecto RStudio tipo WebSite.
Esta es la estructura de carpetas y archivos que nos crea RStudio:
Necesitamos crear, dentro del proyecto, el siguiente esquema de carpetas y archivo: .github/workflows/publish.yml
Dentro del archivo publish_yml vamos a pegar el contenido del Quarto Publishing GitHub Pages
Editaremos este archivo para agregar la indicación a GitHub Actions renderice el tablero en función a un cronograma mediante cron.
Esta configuración cron (obtenida de chatGPT) indica que se repetirá la operación de renderizado todos los lunes a las 8 hs de Argentina:
0 minutos - 11 horas UTC (8 + 3 diferencia con UTC) - * cualquier día del mes - * cualquier mes - 1 primer día de la semana (lunes).
Creamos archivo Quarto dashboard en RStudio y diseñamos su estructura en función de las necesidades.
Para que el archivo pueda renderizar en el sitio de alojamiento necesitamos incluir las fuentes de los paquetes que se utilicen. Esto lo hacemos directamente con el paquete renv que recrea un entorno de trabajo en proyectos como este.
Por lo tanto, vamos a tener que volver a instalar los paquetes que usemos (aún si ya los tenemos instalados en nuestra PC) para que renv los tome.
Luego desde la consola ejecutaremos renv::snapshot() para registrar el estado actual de la biblioteca de paquetes del proyecto en el archivo de bloqueo (lock file).
El tablero debe contener código R que haga la lectura de datos a archivo o archivos en línea, es decir que se accedan desde la web.
Por ejemplo, el siguiente código lee el archivo ejemplo.csv de un repositorio llamado datos-dinamicos de mi cuenta de GitHub.
Además en el diseño del tablero Quarto se puede incluir todo lo conocido que funciona en Quarto basado en Markdown, HTML puro, htmlwidgets o código de Observable JS pero no Shiny. GitHub no tiene soporte nativo y se necesita de servidores especiales para que funcione.
Las fuentes de datos para que un tablero se actualice automáticamente tienen que estar disponibles en la Web.
Algunas variantes de esta situación se dan:
La estructura básica de archivos del proyecto Website de Quarto es:
| Archivo | Descripción |
|---|---|
| index.qmd | Contenido de primera página del sitio |
| about.qmd | Contenido de “acerca de…” del sitio. Se puede eliminar |
| _quarto.yml | Define formato y estructura del sitio |
El tablero puede ser directo, reemplazando el contenido de index.qmd o puede crearse a parte con otro nombre.
about.qmd puede existir con los datos de creación del tablero, equipo de trabajo o autoría, etc.
Los cambios que se realicen tendrán sentido siempre y cuando editemos el archivo de configuración _quarto.yml
project:
type: website
website:
title: "tablero-prueba"
sidebar:
contents:
- href: index.qmd
text: Home
- href: about.qmd
text: Acerca
- href: tablero.qmd
text: TableroEsta configuración de _quarto.yml, por ejemplo, define como “tablero-prueba” al titulo del sitio, crea una barra lateral con tres accesos (Home, Acerca y Tablero)
Además, en el archivo _quarto.yml va el formato y las opciones de ejecución generales (para todo el sitio).
En este caso, estéticas como el tema (cosmo) y el archivo css (styles.css por defecto).
También podríamos sumar un archivo scss de Sass (debemos crearlos dentro de la carpeta del proyecto y configurarlo)
Supongamos que ya tenemos configurado Git en nuestra computadora y una cuenta en GitHub. Vamos a crear un nuevo repositorio para subir el proyecto que estamos construyendo.
A continuación debemos conectar nuestro proyecto de RStudio con el repositorio creado. Hay varios caminos para hacerlo pero el mismo GitHub nos ofrece uno sencillo, utilizando la línea de comandos bash de Git desde la carpeta del proyecto local.
Es decir, que ejecutando esas órdenes le estamos diciendo que el proyecto local se conecte remotamente con el repositorio en GitHub y que suba las subcarpetas y archivos creados hasta ahora.
Otra tarea que debemos hacer dentro de GitHub es una rama (branch) del repositorio con el nombre de gh-pages.
Esta rama contendrá la salida del tablero renderizado automáticamente en el período elegido por nosotros y GitHub Pages vinculará la URL con el contenido.
En Settings del repositorio podemos visualizar como en el apartado Pages, figura que va a implementar desde una rama (Deploy from a branch).
La pestaña Actions debería verse similar a esta.
Los trabajos que figuran son 2: pages-build-deployment y Quarto Publish (este es el que configuramos con el cron).
Observen que al lado de Quarto Publish figura la palabra Scheduled y en pages-build-deployment bot
Instituto Nacional de Epidemiología